// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: linchuan

#include "coin2/exchange/okex_v5_futures/api_order/native_rest_async_asio_subscriber.h"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>

#include "coin2/base/log.h"

namespace coin2::exchange::okex_v5_futures::api_order {

void OkexV5FuturesRestAsyncAsioSubscriber::QueryBalance() {
  auto http_context = rest_client()->QueryAccountInfo();
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void OkexV5FuturesRestAsyncAsioSubscriber::QueryFundBalance() {
  auto http_context = rest_client()->QueryFundBalance();
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void OkexV5FuturesRestAsyncAsioSubscriber::QueryPosition() {
  auto http_context = rest_client()->QueryPositions();
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void OkexV5FuturesRestAsyncAsioSubscriber::QueryOpenOrders(std::string_view after_order_id) {
  auto http_context = rest_client()->QueryOpenOrders(after_order_id);
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void OkexV5FuturesRestAsyncAsioSubscriber::QueryFinishedOrders() {
  auto http_context = rest_client()->QueryHistoryOrders();
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void OkexV5FuturesRestAsyncAsioSubscriber::QueryFills() {
  auto http_context = rest_client()->QueryFills();
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void OkexV5FuturesRestAsyncAsioSubscriber::QueryTransfer() {
  auto http_context = rest_client()->QueryDeposit();
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);

  http_context = rest_client()->QueryWithdrawal();
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void OkexV5FuturesRestAsyncAsioSubscriber::QueryFundingFee() {
  auto http_context = rest_client()->QueryFundingFee();
  if (!http_context) return;
  http_context->handler =
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void OkexV5FuturesRestAsyncAsioSubscriber::SubscribeAsync() {
  AddPeriodicTask(
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::QueryBalance, this),
      config_.query_account_balance_period_sec(),
      "query_balance");

  AddPeriodicTask(
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::QueryPosition, this),
      config_.query_account_position_period_sec(),
      "query_position");

  AddPeriodicTask(
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::QueryOpenOrders, this, ""),
      config_.query_open_orders_period_sec(),
      "query_open_orders");

  AddPeriodicTask(
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::QueryFinishedOrders, this),
      config_.query_cancel_orders_period_sec(),
      "query_finished_orders");

  AddPeriodicTask(
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::QueryFills, this),
      config_.query_fill_period_sec(),
      "query_fills");

  AddPeriodicTask(
      std::bind(&OkexV5FuturesRestAsyncAsioSubscriber::QueryFundingFee, this),
      60 * 5,
      "query_funding_fee");

  // handle number of open order more than 100
  mb_->Subscribe("okex_futures/query_open_orders", [this](const std::string&, void* data) {
    std::string_view after_order_id = *(reinterpret_cast<std::string*>(data));
    this->QueryOpenOrders(after_order_id);
  });
}

}  // namespace coin2::exchange::okex_v5_futures::api_order
